
using System;

//using System.Runtime.InteropServices;
using System.IO;
using Stunt.Nutss;

//using ByteBuffer = java.nio.ByteBuffer;
namespace Stunt.Nutss.Signaling
{

	/// <summary>Encapsulates user data and adds routing information for the proxy network</summary>
	[Serializable]
	class SlingMessage : ISignalingMessage
	{

		#region Enums

		/// <summary>Message type</summary>
		internal enum Type
		{
			/// <summary> Registration related message</summary>
			JSLING_REGISTER,
			/// <summary>
			/// Message sent from a source, to be sent to a particular destination
			/// through multi-hop routing
			/// </summary>
			JSLING_ROUTE,
			/// <summary>Message sent from a proxy, to be sent to the destination in one-hop</summary>
			JSLING_FORWARD
		}

		/// <summary>Response to proxied messages</summary>
		internal enum Response
		{
			/// <summary>Message was not forwarded or process</summary>
			JSLING_ERROR,
			/// <summary>Message was accepted</summary>
			JSLING_SUCCESS
		}

		#endregion

		#region Variables

		/// <summary>Message type</summary>
		internal SlingMessage.Type type;

		/// <summary>Response from proxy network</summary>
		internal SlingMessage.Response response;

		/// <summary>Source</summary>
		internal NutssUri source;

		/// <summary>Intended destination</summary>
		internal NutssUri destination;

		/// <summary>Message ID</summary>
		internal int id;

		/// <summary>Message user data</summary>
		internal object payload;

		/// <summary> Serialized version of the message</summary>
		[NonSerialized]
		internal MemoryStream bbuf;

		/// <summary>Message id of last message created. Used to stamp messages with unique id with wraparound.</summary>
		[NonSerialized]
		private static int last_id = (int)(new Random().NextDouble() * Int32.MaxValue);

		#endregion

		#region Properties

		virtual public bool Error
		{
			get
			{
				return response == Response.JSLING_ERROR;
			}
		}
		virtual public NutssUri Source
		{
			get
			{
				return source;
			}
		}
		virtual public NutssUri Destination
		{
			get
			{
				return destination;
			}
		}
		virtual public object Payload
		{
			get
			{
				return payload;
			}
		}
		virtual public bool HasPayload
		{
			get
			{
				return payload != null;
			}
		}

		#endregion

		#region Constructor

		/// <summary>Creates a new message</summary>
		/// <param name="src">source of message</param>
		/// <param name="dst">destination of message</param>
		/// <param name="payload">message contents</param>
		internal SlingMessage(NutssUri src, NutssUri dst, object payload)
		{
			this.source = src;
			this.destination = dst;
			this.payload = payload;
			this.id = last_id++;
			this.type = Type.JSLING_ROUTE;
		}

		#endregion

		#region Object inherited methods

		public override int GetHashCode()
		{
			// Must match all messages for the same signaling session going
			// either way
			return source.GetHashCode() ^ destination.GetHashCode() ^ id;
		}

		public override bool Equals(object o)
		{

			if (o is SlingMessage)
			{
				// Must match all messages for the same signaling session going
				// either way
				SlingMessage msg = (SlingMessage)o;
				return ((source.Equals(msg.source) && destination.Equals(msg.destination)) || (source.Equals(msg.destination) && destination.Equals(msg.source))) && id == msg.id;
			}

			else
			{
				return false;
			}
		}

		public override string ToString()
		{
			return String.Format("[type={0} response={1} src={2} dst={3} id={4} payload={5}]", type, response, source, destination, id, payload);
		}

		#endregion

	}
}